package com.smartcodes.smartlockrpc.config;

import cn.hutool.db.nosql.redis.RedisDS;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Collections;

/**
 * @ClassName DistributedLock
 * @Description TODO
 * @Author shuang669539827@163.com
 * @Date2019/3/22 17:02
 * @Version v1.0
 **/

public class RedisLock {

    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final String LOCK_PREFIX = "dlock_";
    private static final String LOCK_MSG = "OK";
    private static final Long UNLOCK_MSG = 1L;
    private static final int DEFAULT_EXPIRE_TIME = 60 * 1000;
    private static final long DEFAULT_SLEEP_TIME = 100;
    private Jedis jedis = RedisDS.create().getJedis();


    /**
     * 到redis 中设置锁
     * @param key
     * @param value
     * @return
     * @throws InterruptedException
     */
    private boolean setLockToRedis (String key, String value) throws InterruptedException {
        String result = jedis.set(LOCK_PREFIX + key, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, DEFAULT_EXPIRE_TIME);

        if (LOCK_MSG.equals(result)){
            return true;
        }
//        睡眠
        Thread.sleep(DEFAULT_SLEEP_TIME);
        return false;
    }

    /**
     * 判断指定的key是否锁定
     * @param key
     * @return
     */
    public boolean isLocked(String key){
//       if(null !=  key && !"".equals(key)){
           String result = jedis.get(LOCK_PREFIX + key);
           jedis.close();
           return result != null;
//       }
//        return false;
    }


    /**
     * 清空所有锁
     */
    public void flushAll() {
        jedis.flushAll();
    }

    /**
     * 解锁
     * @param key
     * @param value
     * @return
     */
    public boolean unLock(String key ,String value){
        String script ="if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object eval = jedis.eval(script, Collections.singletonList(LOCK_PREFIX + key), Collections.singletonList(value));
        return UNLOCK_MSG.equals(eval);
    }


    /**
     * 尝试上锁
     * @param key
     * @param value
     * @return
     * @throws InterruptedException
     */
    public boolean tryLock(String key ,String value) throws InterruptedException {
         return setLockToRedis(key ,value);
    }

    /**
     * 循环上锁
     * @param key
     * @param value
     * @return
     */
    public void lock(String key ,String value) throws InterruptedException {
        while (true){
            if(setLockToRedis(key,value)){
                return ;
            }
        }
    }

    /**
     *
     * @param key
     * @param value
     * @param timeOut 尝试多少秒
     * @throws InterruptedException
     */
    public void lock(String key ,String value,int timeOut) throws InterruptedException {
        while (timeOut>=0){
            if (setLockToRedis(key,value)){
                timeOut -= DEFAULT_EXPIRE_TIME;
            }
        }
    }

}
